package gotlib

import (
	"bytes"
	"errors"
	"fmt"
	"math"
	"regexp"
	"strconv"
	"strings"
	"unicode"
	"unicode/utf8"
	"unsafe"
)

const (
	// NotFoundIndex is the position index for string not found in searching functions.
	NotFoundIndex = -1
)

// Chr 返回数字的ascii字符串（0-255）。
func Chr(ascii int) string {
	return string([]byte{byte(ascii % 256)})
}

// BytesToString Bytes转字符串
func BytesToString(data []byte) string {
	return *(*string)(unsafe.Pointer(&data))
}

// StringToBytes 字符串转Bytes
func StringToBytes(data string) []byte {
	return []byte(data)
	//return *(*[]byte)(unsafe.Pointer(&data))
}

// OctToString 代码转换为字符串
func OctToString(str string) string {
	var octReg = regexp.MustCompile(`\\[0-7]{3}`)
	return octReg.ReplaceAllStringFunc(
		str,
		func(s string) string {
			i, _ := strconv.ParseInt(s[1:], 8, 0)
			return string([]byte{byte(i)})
		},
	)
}

// StrReverse 字符串翻转
func StrReverse(str string) string {
	runes := []rune(str)
	for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
		runes[i], runes[j] = runes[j], runes[i]
	}
	return string(runes)
}

// NumberToString float64数字格式化为字符串，可以指定保留小数位数，小数点，千分位
func NumberToString(number float64, decimals int, decPoint, thousandsSep string) string {
	neg := false
	if number < 0 {
		number = -number
		neg = true
	}
	// Will round off
	str := fmt.Sprintf("%."+strconv.Itoa(decimals)+"F", number)
	prefix, suffix := "", ""
	if decimals > 0 {
		prefix = str[:len(str)-(decimals+1)]
		suffix = str[len(str)-decimals:]
	} else {
		prefix = str
	}
	sep := []byte(thousandsSep)
	n, l1, l2 := 0, len(prefix), len(sep)
	// thousands sep num
	c := (l1 - 1) / 3
	tmp := make([]byte, l2*c+l1)
	pos := len(tmp) - 1
	for i := l1 - 1; i >= 0; i, n, pos = i-1, n+1, pos-1 {
		if l2 > 0 && n > 0 && n%3 == 0 {
			for j := range sep {
				tmp[pos] = sep[l2-j-1]
				pos--
			}
		}
		tmp[pos] = prefix[i]
	}
	s := string(tmp)
	if decimals > 0 {
		s += decPoint + suffix
	}
	if neg {
		s = "-" + s
	}

	return s
}

// StrShuffle 打乱字符串顺序
func StrShuffle(str string) string {
	runes := []rune(str)
	s := make([]rune, len(runes))
	for i, v := range RandomIntArray(len(runes)) {
		s[i] = runes[v]
	}
	return string(s)
}

// StrHideMiddle 隐藏字符串中间部分字符为hide字符，一般为*号
func StrHideMiddle(str string, percent int, hide string) string {
	array := strings.Split(str, "@")
	if len(array) > 1 {
		str = array[0]
	}
	var (
		rs     = []rune(str)
		length = len(rs)
		// mid      = math.Floor(float64(length / 2))
		mid     = length / 2
		hideLen = int(math.Floor(float64(length) * (float64(percent) / 100)))
		// start    = int(mid - math.Floor(float64(hideLen)/2))
		start    = mid - hideLen/2
		hideStr  = []rune("")
		hideRune = []rune(hide)
	)
	for i := 0; i < hideLen; i++ {
		hideStr = append(hideStr, hideRune...)
	}
	buffer := bytes.NewBuffer(nil)
	buffer.WriteString(string(rs[0:start]))
	buffer.WriteString(string(hideStr))
	buffer.WriteString(string(rs[start+hideLen:]))
	if len(array) > 1 {
		buffer.WriteString("@" + array[1])
	}
	return buffer.String()
}

// StrToHTML 字符串转HTML显示，把回车转换为<br>或<br />。 isXhtml默认false
func StrToHTML(str string, isXhtml ...bool) string {
	r, n, runes := '\r', '\n', []rune(str)
	var br []byte
	if len(isXhtml) > 0 && isXhtml[0] {
		br = []byte("<br />")
	} else {
		br = []byte("<br>")
	}
	skip := false
	length := len(runes)
	var buf bytes.Buffer
	for i, v := range runes {
		if skip {
			skip = false
			continue
		}
		switch v {
		case n, r:
			if (i+1 < length) && ((v == r && runes[i+1] == n) || (v == n && runes[i+1] == r)) {
				buf.Write(br)
				skip = true
				continue
			}
			buf.Write(br)
		default:
			buf.WriteRune(v)
		}
	}
	return buf.String()
}

// StrWordWrap 字符串文本换行，尽量不切断单词。
func StrWordWrap(str string, width int, br string) string {
	if br == "" {
		br = "\n"
	}
	var (
		current           int
		wordBuf, spaceBuf bytes.Buffer
		init              = make([]byte, 0, len(str))
		buf               = bytes.NewBuffer(init)
		strRunes          = []rune(str)
	)
	if len(strRunes) == 0 {
		return ""
	}
	for _, char := range strRunes {
		switch {
		case char == '\n':
			if wordBuf.Len() == 0 {
				if current+spaceBuf.Len() > width {
					current = 0
				} else {
					current += spaceBuf.Len()
					_, _ = spaceBuf.WriteTo(buf)
				}
				spaceBuf.Reset()
			} else {
				current += spaceBuf.Len() + wordBuf.Len()
				_, _ = spaceBuf.WriteTo(buf)
				spaceBuf.Reset()
				_, _ = wordBuf.WriteTo(buf)
				wordBuf.Reset()
			}
			buf.WriteRune(char)
			current = 0

		case unicode.IsSpace(char):
			if spaceBuf.Len() == 0 || wordBuf.Len() > 0 {
				current += spaceBuf.Len() + wordBuf.Len()
				_, _ = spaceBuf.WriteTo(buf)
				spaceBuf.Reset()
				_, _ = wordBuf.WriteTo(buf)
				wordBuf.Reset()
			}
			spaceBuf.WriteRune(char)

		case CharIsPunctuation(char):
			wordBuf.WriteRune(char)
			if spaceBuf.Len() == 0 || wordBuf.Len() > 0 {
				current += spaceBuf.Len() + wordBuf.Len()
				_, _ = spaceBuf.WriteTo(buf)
				spaceBuf.Reset()
				_, _ = wordBuf.WriteTo(buf)
				wordBuf.Reset()
			}

		default:
			wordBuf.WriteRune(char)
			if current+spaceBuf.Len()+wordBuf.Len() > width && wordBuf.Len() < width {
				buf.WriteString(br)
				current = 0
				spaceBuf.Reset()
			}
		}
	}

	if wordBuf.Len() == 0 {
		if current+spaceBuf.Len() <= width {
			_, _ = spaceBuf.WriteTo(buf)
		}
	} else {
		_, _ = spaceBuf.WriteTo(buf)
		_, _ = wordBuf.WriteTo(buf)
	}
	return buf.String()
}

// StrIndex 从某个位置开始，查找子字符串在字符串中的位置。大小写敏感。找不到返回-1
func StrIndex(str, substring string, startOffset ...int) int {
	length := len(str)
	offset := 0
	if len(startOffset) > 0 {
		offset = startOffset[0]
	}
	if length == 0 || offset > length || -offset > length {
		return -1
	}
	if offset < 0 {
		offset += length
	}
	pos := strings.Index(str[offset:], substring)
	if pos == NotFoundIndex {
		return NotFoundIndex
	}
	return pos + offset
}

// StrIndexI 从某个位置开始，查找子字符串在字符串中的位置。大小写不敏感。找不到返回-1 case-insensitively
func StrIndexI(str, substring string, startOffset ...int) int {
	length := len(str)
	offset := 0
	if len(startOffset) > 0 {
		offset = startOffset[0]
	}
	if length == 0 || offset > length || -offset > length {
		return -1
	}

	if offset < 0 {
		offset += length
	}
	pos := strings.Index(strings.ToLower(str[offset:]), strings.ToLower(substring))
	if pos == -1 {
		return -1
	}
	return pos + offset
}

// StrIndexBack 从后面某个位置开始，查找子字符串在字符串中的位置。大小写敏感。找不到返回-1
func StrIndexBack(str, substring string, startOffset ...int) int {
	offset := 0
	if len(startOffset) > 0 {
		offset = startOffset[0]
	}
	pos, length := 0, len(str)
	if length == 0 || offset > length || -offset > length {
		return -1
	}

	if offset < 0 {
		str = str[:offset+length+1]
	} else {
		str = str[offset:]
	}
	pos = strings.LastIndex(str, substring)
	if offset > 0 && pos != -1 {
		pos += offset
	}
	return pos
}

// StrIndexBackI 从后面某个位置开始，查找子字符串在字符串中的位置。大小写不敏感。找不到返回-1
func StrIndexBackI(str, substring string, startOffset ...int) int {
	offset := 0
	if len(startOffset) > 0 {
		offset = startOffset[0]
	}
	pos, length := 0, len(str)
	if length == 0 || offset > length || -offset > length {
		return -1
	}

	if offset < 0 {
		str = str[:offset+length+1]
	} else {
		str = str[offset:]
	}
	pos = strings.LastIndex(strings.ToLower(str), strings.ToLower(substring))
	if offset > 0 && pos != -1 {
		pos += offset
	}
	return pos
}

// StrUnicodeIndex Unicode字符串位置查询,大小写敏感
func StrUnicodeIndex(str, substring string, startOffset ...int) int {
	pos := StrIndex(str, substring, startOffset...)
	if pos < 3 {
		return pos
	}
	return len([]rune(str[:pos]))
}

// StrUnicodeIndexI Unicode字符串位置查询,大小写不敏感
func StrUnicodeIndexI(str, substring string, startOffset ...int) int {
	pos := StrIndexI(str, substring, startOffset...)
	if pos < 3 {
		return pos
	}
	return len([]rune(str[:pos]))
}

// StrBackUnicodeIndex Unicode字符串从后面开始位置查询,大小写敏感
func StrBackUnicodeIndex(str, substring string, startOffset ...int) int {
	pos := StrIndexBack(str, substring, startOffset...)
	if pos < 3 {
		return pos
	}
	return len([]rune(str[:pos]))
}

// StrBackUnicodeIndexI Unicode字符串从后面开始位置查询,大小写不敏感
func StrBackUnicodeIndexI(str, substring string, startOffset ...int) int {
	pos := StrIndexBackI(str, substring, startOffset...)
	if pos < 3 {
		return pos
	}
	return len([]rune(str[:pos]))
}

// StrLeftL 返回第一个子字符串左侧字符串。含子字符串
func StrLeftL(str, substring string) string {
	iPos := StrIndex(str, substring, 0)
	if iPos > 0 {
		return str[:iPos+len(substring)]
	} else {
		return ""
	}
}

// StrRightL 返回第一个子字符串右侧字符串。含子字符串
func StrRightL(str, substring string) string {
	iPos := StrIndex(str, substring, 0)
	if iPos >= 0 {
		return str[iPos:]
	} else {
		return ""
	}
}

// StrLeftBackL 返回第一个子字符串左侧字符串。含子字符串
func StrLeftBackL(str, substring string) string {
	iPos := StrIndexBack(str, substring, 0)
	if iPos > 0 {
		return str[:iPos+len(substring)]
	} else {
		return ""
	}
}

// StrRightBackL 返回第一个子字符串右侧字符串。含子字符串
func StrRightBackL(str, substring string) string {
	iPos := StrIndexBack(str, substring, 0)
	if iPos >= 0 {
		return str[iPos:]
	} else {
		return ""
	}
}

// StrLeft 返回第一个子字符串左侧字符串。
func StrLeft(str, substring string) string {
	iPos := StrIndex(str, substring, 0)
	if iPos > 0 {
		return str[:iPos]
	} else {
		return ""
	}
}

// StrRight 返回第一个子字符串右侧字符串。
func StrRight(str, substring string) string {
	iPos := StrIndex(str, substring, 0)
	if iPos >= 0 {
		return str[iPos+len(substring):]
	} else {
		return ""
	}
}

// StrLeftBack 返回第一个子字符串左侧字符串。
func StrLeftBack(str, substring string) string {
	iPos := StrIndexBack(str, substring, 0)
	if iPos > 0 {
		return str[:iPos]
	} else {
		return ""
	}
}

// StrRightBack 返回第一个子字符串右侧字符串。
func StrRightBack(str, substring string) string {
	iPos := StrIndexBack(str, substring, 0)
	if iPos >= 0 {
		return str[iPos+len(substring):]
	} else {
		return ""
	}
}

// StrArrayIndex SearchArray searches string `s` in string slice `a` case-sensitively,
// returns its index in `a`.
// If `s` is not found in `a`, it returns -1.
func StrArrayIndex(a []string, s string) int {
	for i, v := range a {
		if s == v {
			return i
		}
	}
	return NotFoundIndex
}

// InArray checks whether string `s` in slice `a`.
func InArray(a []string, s string) bool {
	return StrArrayIndex(a, s) != NotFoundIndex
}

// StrArrayInArray = InArray checks whether string `s` in slice `a`.
func StrArrayInArray(a []string, s string) bool {
	return StrArrayIndex(a, s) != NotFoundIndex
}

// StrArrayRemoveItem 字符串数组，删除条目
func StrArrayRemoveItem(a []string, item string) []string {
	for i, v := range a {
		if item == v {
			a = append(a[:i], a[i+1:]...)
			return a
		}
	}
	return a
}

// StrArrayAppendIfNotExist 字符串数组条件追加，如果原数组中不存在新项目就追加
func StrArrayAppendIfNotExist(a []string, item string) []string {
	if StrArrayIndex(a, item) == NotFoundIndex {
		return append(a, item)
	}
	return a
}

// StrArrayReplace 字符串数组替换
func StrArrayReplace(sourceArray []string, from, to string) (retArray []string) {
	for _, v := range sourceArray {
		if v == from {
			retArray = append(retArray, to)
		} else {
			retArray = append(retArray, v)
		}
	}
	return
}

// PrefixArray adds `prefix` string for each item of `array`.
func PrefixArray(array []string, prefix string) {
	for k, v := range array {
		array[k] = prefix + v
	}
}

//   | Function                          | Result             |
//   |-----------------------------------|--------------------|
//   | CaseSnakeLower(s)                 | any_kind_of_string |
//   | CaseSnakeUpper(s)                 | ANY_KIND_OF_STRING |
//   | CaseSnakeLowerByFirstUpper("RGBCodeMd5") | rgb_code_md5       |
//   | CaseKebabLower(s)                 | any-kind-of-string |
//   | CaseKebabUpper(s)                 | ANY-KIND-OF-STRING |
//   | CaseDelimitedLower(s, '.')             | any.kind.of.string |
//   | CaseDelimitedUpper(s, '.')    | ANY.KIND.OF.STRING |
//   | CaseCamel(s)                      | AnyKindOfString    |
//   | CaseCamelLower(s)                 | anyKindOfString    |

var (
	numberSequence      = regexp.MustCompile(`([a-zA-Z]{0,1})(\d+)([a-zA-Z]{0,1})`)
	firstCamelCaseStart = regexp.MustCompile(`([A-Z]+)([A-Z]?[_a-z\d]+)|$`)
	firstCamelCaseEnd   = regexp.MustCompile(`([\w\W]*?)([_]?[A-Z]+)$`)
)

// CaseCamelUpper converts a string to CamelCase.
func CaseCamelUpper(s string) string {
	return toCamelInitCase(s, true)
}

// CaseCamelLower converts a string to lowerCamelCase.
func CaseCamelLower(s string) string {
	if s == "" {
		return s
	}
	if r := rune(s[0]); r >= 'A' && r <= 'Z' {
		s = strings.ToLower(string(r)) + s[1:]
	}
	return toCamelInitCase(s, false)
}

// CaseSnakeLower 字符串转换为下划线分割的小写字母字符串 converts a string to snake_case.
func CaseSnakeLower(s string) string {
	return CaseDelimited(s, '_', false)
}

// CaseSnakeUpper 字符串转换为下划线分割的大写字母字符串 converts a string to SNAKE_CASE_SCREAMING.
func CaseSnakeUpper(s string) string {
	return CaseDelimited(s, '_', true)
}

// CaseSnakeLowerByFirstUpper 根据首字母大写规则转换为全部小写下划线分割字符串 converts a string like "BGColor" to "bg_color".
// TODO for efficiency should change regexp to traversing string in future.
func CaseSnakeLowerByFirstUpper(word string, underscore ...string) string {
	replace := "_"
	if len(underscore) > 0 {
		replace = underscore[0]
	}

	m := firstCamelCaseEnd.FindAllStringSubmatch(word, 1)
	if len(m) > 0 {
		word = m[0][1] + replace + strings.TrimLeft(strings.ToLower(m[0][2]), replace)
	}

	for {
		m = firstCamelCaseStart.FindAllStringSubmatch(word, 1)
		if len(m) > 0 && m[0][1] != "" {
			w := strings.ToLower(m[0][1])
			w = w[:len(w)-1] + replace + string(w[len(w)-1])

			word = strings.Replace(word, m[0][1], w, 1)
		} else {
			break
		}
	}

	return strings.TrimLeft(word, replace)
}

// CaseKebabLower 转换为羊肉串式小写字母字符串 converts a string to kebab-case
func CaseKebabLower(s string) string {
	return CaseDelimited(s, '-', false)
}

// CaseKebabUpper 转换为羊肉串式大写字母字符串 converts a string to KEBAB-CASE-SCREAMING.
func CaseKebabUpper(s string) string {
	return CaseDelimited(s, '-', true)
}

// CaseDelimitedLower 字符串句号分割转换为小写字母 converts a string to snake.case.delimited.
func CaseDelimitedLower(s string, del byte) string {
	return CaseDelimited(s, del, false)
}

// CaseDelimitedUpper 字符串句号分割转换为大写字母 converts a string to snake.case.delimited.
func CaseDelimitedUpper(s string, del byte) string {
	return CaseDelimited(s, del, true)
}

// CaseDelimited 字符串自动分割转换为小写或大写字母converts a string to DELIMITED.SCREAMING.CASE or delimited.screaming.case.
func CaseDelimited(s string, del uint8, screaming bool) string {
	s = addWordBoundariesToNumbers(s)
	s = strings.Trim(s, " ")
	n := ""
	for i, v := range s {
		// treat acronyms as words, eg for JSONData -> JSON is a whole word
		nextCaseIsChanged := false
		if i+1 < len(s) {
			next := s[i+1]
			if (v >= 'A' && v <= 'Z' && next >= 'a' && next <= 'z') || (v >= 'a' && v <= 'z' && next >= 'A' && next <= 'Z') {
				nextCaseIsChanged = true
			}
		}

		if i > 0 && n[len(n)-1] != del && nextCaseIsChanged {
			// add underscore if next letter case type is changed
			if v >= 'A' && v <= 'Z' {
				n += string(del) + string(v)
			} else if v >= 'a' && v <= 'z' {
				n += string(v) + string(del)
			}
		} else if v == ' ' || v == '_' || v == '-' || v == '.' {
			// replace spaces/underscores with delimiters
			n += string(del)
		} else {
			n = n + string(v)
		}
	}

	if screaming {
		n = strings.ToUpper(n)
	} else {
		n = strings.ToLower(n)
	}
	return n
}

func addWordBoundariesToNumbers(s string) string {
	r := numberSequence.ReplaceAllFunc([]byte(s), func(bytes []byte) []byte {
		var result []byte
		match := numberSequence.FindSubmatch(bytes)
		if len(match[1]) > 0 {
			result = append(result, match[1]...)
			result = append(result, []byte(" ")...)
		}
		result = append(result, match[2]...)
		if len(match[3]) > 0 {
			result = append(result, []byte(" ")...)
			result = append(result, match[3]...)
		}
		return result
	})
	return string(r)
}

// Converts a string to CamelCase
func toCamelInitCase(s string, initCase bool) string {
	s = addWordBoundariesToNumbers(s)
	s = strings.Trim(s, " ")
	n := ""
	capNext := initCase
	for _, v := range s {
		if v >= 'A' && v <= 'Z' {
			n += string(v)
		}
		if v >= '0' && v <= '9' {
			n += string(v)
		}
		if v >= 'a' && v <= 'z' {
			if capNext {
				n += strings.ToUpper(string(v))
			} else {
				n += string(v)
			}
		}
		if v == '_' || v == ' ' || v == '-' || v == '.' {
			capNext = true
		} else {
			capNext = false
		}
	}
	return n
}

// CharIsPunctuation 判读是否是一般不用于行开头的标点符号
func CharIsPunctuation(char int32) bool {
	switch char {
	// English Punctuations.
	case ';', '.', ',', ':', '~':
		return true
	// Chinese Punctuations.
	case '；', '，', '。', '：', '？', '！', '…', '、':
		return true
	default:
		return false
	}
}

// StrCount 查找字符串中子字符串的数量
func StrCount(s, substr string) int {
	return strings.Count(s, substr)
}

// StrCountI 查找字符串中子字符串的数量,忽略大小写
func StrCountI(s, substr string) int {
	return strings.Count(strings.ToLower(s), strings.ToLower(substr))
}

// StrCountWords 计算每个单词的数量，返回map[string]int
func StrCountWords(str string) map[string]int {
	m := make(map[string]int)
	buffer := bytes.NewBuffer(nil)
	strRune := []rune(str)
	if len(strRune) == 0 {
		return m
	}
	for _, r := range strRune {
		if unicode.IsSpace(r) {
			if buffer.Len() > 0 {
				m[buffer.String()]++
				buffer.Reset()
			}
		} else {
			buffer.WriteRune(r)
		}
	}
	if buffer.Len() > 0 {
		m[buffer.String()]++
	}
	return m
}

// StrCountChars 计算每个单词的数量，返回map[string]int
func StrCountChars(str string, noSpace ...bool) map[string]int {
	m := make(map[string]int)
	countSpace := true
	if len(noSpace) > 0 && noSpace[0] {
		countSpace = false
	}
	strRune := []rune(str)
	if len(strRune) == 0 {
		return m
	}
	for _, r := range strRune {
		if !countSpace && unicode.IsSpace(r) {
			continue
		}
		m[string(r)]++
	}
	return m
}

func StrIsNumeric(s string) bool {
	var (
		dotCount = 0
		length   = len(s)
	)
	if length == 0 {
		return false
	}
	for i := 0; i < length; i++ {
		if s[i] == '-' && i == 0 {
			continue
		}
		if s[i] == '.' {
			dotCount++
			if i > 0 && i < length-1 {
				continue
			} else {
				return false
			}
		}
		if s[i] < '0' || s[i] > '9' {
			return false
		}
	}
	if dotCount > 1 {
		return false
	}
	return true
}

// StrUTFLen 获取UTF8字符串的长度
func StrUTFLen(str string) int {
	return utf8.RuneCountInString(str)
}

// StrParse 请使用 url.ParseQuery
func StrParse() error {
	return errors.New("请使用 url.ParseQuery")
}

// StrReplace 字符串替换，区分大小写。不设置替换次数代表全部替换。
func StrReplace(origin, search, replace string, replaceCount ...int) string {
	n := -1
	if len(replaceCount) > 0 {
		n = replaceCount[0]
	}
	return strings.Replace(origin, search, replace, n)
}

// StrReplaceI 字符串替换，不区分大小写。不设置替换次数代表全部替换。
func StrReplaceI(origin, search, replace string, count ...int) string {
	n := -1
	if len(count) > 0 {
		n = count[0]
	}
	if n == 0 {
		return origin
	}
	var (
		searchLength  = len(search)
		replaceLength = len(replace)
		searchLower   = strings.ToLower(search)
		originLower   string
		pos           int
	)
	for {
		originLower = strings.ToLower(origin)
		if pos = StrIndex(originLower, searchLower, pos); pos != -1 {
			origin = origin[:pos] + replace + origin[pos+searchLength:]
			pos += replaceLength
			if n--; n == 0 {
				break
			}
		} else {
			break
		}
	}
	return origin
}

// StrReplaceByArray 根据成对的Array内容进行依次全部替换,不成对出现时，数组最后一个忽略。
func StrReplaceByArray(origin string, array []string) string {
	for i := 0; i < len(array); i += 2 {
		if i+1 >= len(array) {
			break
		}
		origin = StrReplace(origin, array[i], array[i+1])
	}
	return origin
}

// StrReplaceIByArray 根据成对的Array内容进行依次全部替换,不成对出现时，数组最后一个忽略。大小写不敏感
func StrReplaceIByArray(origin string, array []string) string {
	for i := 0; i < len(array); i += 2 {
		if i+1 >= len(array) {
			break
		}
		origin = StrReplaceI(origin, array[i], array[i+1])
	}
	return origin
}

// StrReplaceByMap 根据map内容进行依次全部替换。
func StrReplaceByMap(origin string, replaces map[string]string) string {
	for k, v := range replaces {
		origin = strings.Replace(origin, k, v, -1)
	}
	return origin
}

// StrReplaceIByMap 根据map内容进行依次全部替换。大小写不敏感
func StrReplaceIByMap(origin string, replaces map[string]string) string {
	for k, v := range replaces {
		origin = StrReplaceI(origin, k, v)
	}
	return origin
}

// StrAddLineNumber 前面加上行号
func StrAddLineNumber(str string) string {
	lines := strings.Split(str, "\n")
	for k, v := range lines {
		if k == 0 {
			lines[k] = StrJoin("", strconv.Itoa(k+1), " ", v)
		} else {
			lines[k] = StrJoin("", "\n", strconv.Itoa(k+1), " ", v)
		}
	}
	return strings.Join(lines, "")
}

// StrAddSlashes 格式化字符串中的指定字符前增加斜杠字符，默认转换的字符有 .\+*?[^]($) 可以自定义
func StrAddSlashes(str string, chars ...string) string {
	var buf bytes.Buffer
	for _, char := range str {
		if len(chars) > 0 {
			for _, c := range chars[0] {
				if c == char {
					buf.WriteRune('\\')
					break
				}
			}
		} else {
			switch char {
			case '.', '+', '\\', '(', '$', ')', '[', '^', ']', '*', '?':
				buf.WriteRune('\\')
			}
		}
		buf.WriteRune(char)
	}
	return buf.String()
}

// StrRemoveSlashes 去除字符串中的斜杠字符
func StrRemoveSlashes(str string) string {
	var buf bytes.Buffer
	l, skip := len(str), false
	for i, char := range str {
		if skip {
			skip = false
		} else if char == '\\' {
			if i+1 < l && str[i+1] == '\\' {
				skip = true
			}
			continue
		}
		buf.WriteRune(char)
	}
	return buf.String()
}

// StrTrim 去除字符串两侧的空字符及指定字符。
// 默认包含：Tab, Vertical tab, New line, Carriage return, New page, Ordinary space, NUL, Delete, Non-breaking space.
func StrTrim(str string, characterMask ...string) string {
	var DefaultTrimChars = string([]byte{
		'\t', // Tab.
		'\v', // Vertical tab.
		'\n', // New line (line feed).
		'\r', // Carriage return.
		'\f', // New page.
		' ',  // Ordinary space.
		0x00, // NUL-byte.
		0x85, // Delete.
		0xA0, // Non-breaking space.
	})
	trimChars := DefaultTrimChars
	if len(characterMask) > 0 {
		trimChars += characterMask[0]
	}
	return strings.Trim(str, trimChars)
}

// StrSplitAndTrim 字符串分割后再做Trim
func StrSplitAndTrim(str, delimiter string, characterMask ...string) []string {
	array := make([]string, 0)
	for _, v := range strings.Split(str, delimiter) {
		v = StrTrim(v, characterMask...)
		if v != "" {
			array = append(array, v)
		}
	}
	return array
}

// StrJoin 以split做为分割符号，把str内容进行连接
func StrJoin(split string, str ...string) string {
	return strings.Join(str, split)
}

// StrJoinAny 以split做为分割符号，把any内容进行连接
func StrJoinAny(split string, any ...interface{}) string {
	str := ""
	for _, item := range any {
		if str == "" {
			str = String(item)
		} else {
			str = strings.Join([]string{str, String(item)}, split)
		}
	}
	return str
}

// StrSplitWord 字符串切割为单词字符串数组
func StrSplitWord(str string) []string {
	return strings.Fields(str)
}

// StrMiddle 获取字符串start位置开始，长度为length
func StrMiddle(str string, start int64, length ...int64) (substr string) {
	strLength := Int64(len(str))

	if start < 0 {
		start = 0
	}
	if start >= strLength {
		start = strLength
	}
	end := strLength
	if len(length) > 0 {
		end = start + length[0]
		if end < start {
			end = strLength
		}
	}
	if end > strLength {
		end = strLength
	}
	return str[start:end]
}

// StrLimit 字符串超长用默认...或指定内容替换结尾。
func StrLimit(str string, length int, suffix ...string) string {
	if len(str) < length {
		return str
	}
	suffixStr := "..."
	if len(suffix) > 0 {
		suffixStr = suffix[0]
	}
	return str[0:length] + suffixStr
}

// StrLimitUnicode 字符串超长用默认...或指定内容替换结尾。支持unicode
func StrLimitUnicode(str string, length int, suffix ...string) string {
	runes := []rune(str)
	if len(runes) < length {
		return str
	}
	suffixStr := "..."
	if len(suffix) > 0 {
		suffixStr = suffix[0]
	}
	return string(runes[0:length]) + suffixStr
}

// StrFirstUpper 首字母大写
func StrFirstUpper(s string) string {
	if len(s) == 0 {
		return s
	}
	if IsLetterLower(s[0]) {
		return string(s[0]-32) + s[1:]
	}
	return s
}

// StrFirstLower 首字母小写
func StrFirstLower(s string) string {
	if len(s) == 0 {
		return s
	}
	if IsLetterUpper(s[0]) {
		return string(s[0]+32) + s[1:]
	}
	return s
}

// StrWordsFirstUpper 字符串每个单词首字母大写
func StrWordsFirstUpper(str string) string {
	return strings.Title(str)
}

// IsLetterUpper checks whether the given byte b is in upper case.
func IsLetterUpper(b byte) bool {
	if b >= byte('A') && b <= byte('Z') {
		return true
	}
	return false
}

// IsLetterLower checks whether the given byte b is in lower case.
func IsLetterLower(b byte) bool {
	if b >= byte('a') && b <= byte('z') {
		return true
	}
	return false
}

// StrReplaceBraceByMap 双括号内容替换：根据map信息，替换{{k}}为v，
func StrReplaceBraceByMap(str string, m map[string]string) string {
	for k, v := range m {
		temp := StrJoin("{{", k, "}}")
		if strings.Index(str, temp) >= 0 {
			str = strings.ReplaceAll(str, temp, v)
		}
	}
	return str
}

// StrReplaceBraceByMapStrInterface 双括号内容替换：根据map信息，替换{{k}}为v，
func StrReplaceBraceByMapStrInterface(str string, m map[string]interface{}) string {
	for k, v := range m {
		temp := StrJoin("{{", k, "}}")
		if strings.Index(str, temp) >= 0 {
			str = strings.ReplaceAll(str, temp, String(v))
		}
	}
	return str
}

// StrLeftLength 获取字符串左侧指定长度的字符串
func StrLeftLength(str string, length int) string {
	if len(str) < length {
		return str
	}
	return str[0:length]
}

// StrRightLength 获取字符串右侧指定长度的字符串
func StrRightLength(str string, length int) string {
	if len(str) < length {
		return str
	}
	return str[len(str)-length:]
}

// StrLeftLengthBack 获取字符串左侧指定长度的字符串之后的字符串
func StrLeftLengthBack(str string, length int) string {
	if len(str) < length {
		return ""
	}
	return str[length:]
}

// StrRightLengthBack 获取字符串右侧指定长度的字符串之前的字符串
func StrRightLengthBack(str string, length int) string {
	if len(str) < length {
		return ""
	}
	return str[0 : len(str)-length]
}

// PadLeft 在字符串左侧填充字符到指定长度
// str: 要填充的字符串
// length: 期望的总长度
// pad: 填充用的字符
func PadLeft(str string, length int, pad string) string {
	if len(str) >= length {
		return str
	}

	return strings.Repeat(pad, length-len(str)) + str
}

// GetValueByKey 获取key对应的value值
// str:字符串格式："key1:value1,key2:value2,key3:value3"
// key:key值
func GetValueByKey(str string, key string) (value string) {
	arr := strings.Split(str, ",")
	for _, v := range arr {
		if strings.Index(str, ":") < 1 {
			continue
		}
		kv := strings.Split(v, ":")
		if kv[0] == key {
			return kv[1]
		}
	}
	return ""
}

// StrToMap 获取字符串的map, string格式："key1:value1,key2:value2,key3:value3"
func StrToMap(str string) (map[string]string, error) {
	arr := strings.Split(str, ",")
	retMap := make(map[string]string)
	for _, v := range arr {
		if strings.Index(str, ":") < 1 {
			continue
		}
		kv := strings.Split(v, ":")
		if len(kv) != 2 {
			return nil, errors.New("error format")
		}
		retMap[kv[0]] = kv[1]
	}
	return retMap, nil
}

// StrOutline 获取字符串的outline; 1.2.3 => 001002003
func StrOutline(outline string) (value string) {
	x := strings.Split(outline, ".")
	for _, str := range x {
		value = value + PadLeft(str, 3, "0")
	}
	return
}
